#!/usr/bin/env python

'''
A game to be played through a socket connection, arbitred by a controller
using GTP.

Alternatively, the commands can be read and sent by the console.
'''
from GTPEngine import GTPEngine
from optparse import OptionParser
from socket import socket, AF_INET, SOCK_STREAM
import sys
from pygo1963.model.PlayersFactory import ALPHA_BETA_KEY, HUMAN_KEY, RANDOM_KEY,\
    create_player
from pygo1963.view.View import View, GameView
from pygo1963.view.main import view_loop

class NetworkGame():
    """ A Go game to be played through a remote connection. """
    
    def __init__(self, engine, use_sockets=False, host=None, port=None):
        
        self.engine = engine
        
        self.next_move = None
        
        if options.use_sockets:
            logger.write('trying to make socket on %s, %d\n' % (options.host,
                                                               options.port))        
            self.sockobj = socket(AF_INET, SOCK_STREAM)
            self.sockobj.connect((options.host, options.port))
            
            logger.write('making socket file.\n')
            self.in_file = self.out_file = self.sockobj.makefile()            
                    
        else:
            self.in_file = sys.stdin
            self.out_file = sys.stdout
            
            self.sockobj = None
    
    def __getattr__(self, name):
        
        if name == 'board':
            return self.engine.board
        else:
            raise AttributeError
        
    #TODO cerrar archivos cuando termina
    def play(self):
        """ Game loop. """
        
        logger.write('starting play.\n')
        while not self.engine.received_quit:
                
            cmd = ''
            while not cmd: 
                cmd = self._preprocess_command(self.in_file.readline())
            logger.write('command read: ' + cmd)
            
            response = engine.process_command(cmd)
            logger.write('response sent: ' + response)
            
            self.out_file.write(response)
            self.out_file.flush()
    
        self.finish()

    def _preprocess_command(self, command):
        """ Removes control characters and comments from the command. """
        
        #Remove control chars except HT and LF
        del_chars = ''.join(chr(n) for n in range(9) + range(11,32))    
        command = command.translate(None, del_chars)
        
        #Convert HT to spaces
        command.replace('\t', ' ')
        
        #remove comments
        index = command.find('#')
        if index != -1:
            command = command[:index]
        
        #if its only whitespaces make it empty
        if command.isspace():
            return ''
        
        return command
    
    def finish(self):
        """ Makes the necessary cleanup after the game has finished. """
        
        if self.sockobj:
            self.out_file.close()
            self.sockobj.close()
            


def parse_options():
    parser = OptionParser()
    parser.add_option('-c', '--color', action='store', dest='color',
                      type='choice', choices=('b', 'w', 'black', 'white'), 
                      default='b')
    parser.add_option('-e', '--engine', action='store', dest='player',
                      type='choice', choices=(ALPHA_BETA_KEY, HUMAN_KEY, RANDOM_KEY), 
                      default=ALPHA_BETA_KEY)
    parser.add_option('-s', '--use-sockets', action='store_true', 
                      dest='use_sockets', default=False)
    parser.add_option('-i', '--host', action='store', dest='host', 
                      default='localhost')
    parser.add_option('-p', '--port', action='store', dest='port', type="int",
                      default='50007')
    return parser.parse_args()[0]


#MAIN PROGRAM
if __name__ == "__main__":
    options = parse_options()
    
    view = View()    
    
    logger = open('network.%s.log' % options.color, 'w')
    
    engine = GTPEngine(create_player(options.player, options.color, view.controller))    
    game = NetworkGame(engine, options.use_sockets, options.host, options.port)
    GameView(view, game)

    view_loop(view)
        
    logger.close()
        